#include "HelpFun.h"
#include "DumpLog.h"
#include <sstream>
#include <iomanip>
#include <unistd.h>
#include <limits.h>
namespace Help
{

void writeVecValue(File &fw, const VectorXd_t &inDatas)
{
    //1.
    fw.write<uint32_t>(inDatas.size());

    //2.
    for (auto v : inDatas)
    {
        fw.write<value_t>(v);
    }
}

void writeVecValue(File &fw, const vecValue_t &inDatas)
{
    //1.
    fw.write<uint32_t>(inDatas.size());

    //2.
    for (auto v : inDatas)
    {
        fw.write<value_t>(v);
    }
}

void readVecValue(File &fr, VectorXd_t &outDatas)
{
    //1.
    uint32_t n = fr.read<uint32_t>();

    //2.
    outDatas.resize(n);
    for (uint32_t i = 0; i != n; ++i)
    {
        outDatas[i] = fr.read<value_t>();
    }
}

void readVecValue(File &fr, vecValue_t &outDatas)
{
    //1.
    uint32_t n = fr.read<uint32_t>();

    //2.
    outDatas.clear();
    for (;n; --n)
    {
        outDatas.push_back(fr.read<value_t>());
    }
}

std::string printVecValue(const VectorXd_t &x)
{
    //1.
    if (x.size() == 0)
    {
        return "";
    }

    //2.
    std::ostringstream ss;
    ss << std::setprecision(16) << x[0];
    for (Eigen::Index i = 1; i != x.size(); ++i)
    {
        ss << "\n" << x[i];
    }

    return ss.str();
}

bool strIsNumber(const std::string &s)
{
    //1.
    if (s.empty())
    {
        return false;
    }

    //2.
    for (auto c : s)
    {
        if (c < '0' || c > '9')
        {
            return false;
        }
    }

    //3.
    return true;
}

bool tryToInt64(const std::string &s, int64_t &ret, const int64_t defaultValue, const int64_t minValue, const int64_t maxValue, const std::string &errorNote)
{
    //1.
    ret = defaultValue;

    //2.
    if (s.size() > 19 || s.empty())
    {
        if (errorNote.size())
        {
            LogError(errorNote);
        }

        return false;
    }

    //3.
    bool neg(false);
    std::string v(s);
    if (s[0] == '-')
    {
        neg = true;
        v   = s.substr(1, s.size() - 1);
    }

    //4.
    if (!strIsNumber(v))
    {
        if (errorNote.size())
        {
            LogError(errorNote);
        }

        return false;
    }

    //5.
    ret = std::stoll(v);
    if (neg)
    {
        ret = -ret;
    }

    //6.
    if (ret < minValue || ret > maxValue)
    {
        if (errorNote.size())
        {
            LogError(errorNote);
        }

        return false;
    }

    //7.
    return true;
}

bool tryToDouble(const std::string &s, long double &ret, const long double defaultValue, const long double minValue, const long double maxValue, const std::string &errorNote)
{
    //1.
    ret = defaultValue;

    //2.
    if (s.empty() || s.size() > 50)
    {
        if (errorNote.size())
        {
            LogError(errorNote);
        }

        return false;
    }

    //3.
    std::string a("1"), b("0");
    std::size_t i = s.find('e');
    if (i == std::string::npos)
    {
        i = s.find('E');
    }

    if (i == std::string::npos || i + 1 == s.size())
    {
        a = s;
    }
    else
    {
        if (i)
        {
            a = s.substr(0, i);
            ++i;
            if (s[i] == '+')
            {
                ++i;
                if (i == s.size())
                {
                    if (errorNote.size())
                    {
                        LogError(errorNote);
                    }

                    return false;
                }
            }

            b = s.substr(i, s.size() - i);
        }
        else
        {
            b = s;
        }
    }

    //4.
    int64_t bn(0);
    if (!tryToInt64(b, bn, 0, -300, 300))
    {
        if (errorNote.size())
        {
            LogError(errorNote);
        }

        return false;
    }

    //5.
    long double an(1);
    if (!a.empty())
    {
        bool neg = (a[0] == '-');
        if (neg)
        {
            a = a.substr(1, a.size() - 1);
        }

        if (a.empty())
        {
            if (errorNote.size())
            {
                LogError(errorNote);
            }

            return false;
        }

        i = a.find('.');
        if (i != std::string::npos)
        {
            if (i == 0 || i + 1 == a.size())
            {
                if (errorNote.size())
                {
                    LogError(errorNote);
                }

                return false;
            }

            if (!strIsNumber(a.substr(0, i)) || !strIsNumber(a.substr(i+1, a.size() - i - 1)))
            {
                if (errorNote.size())
                {
                    LogError(errorNote);
                }

                return false;
            }
        }
        else if(!strIsNumber(a))
        {
            if (errorNote.size())
            {
                LogError(errorNote);
            }

            return false;
        }

        an = std::stold(a);
        if (neg)
        {
            an = -an;
        }
    }

    if (bn)
    {
        an *= std::pow(10, bn);
    }

    //6.
    if (an < minValue || an > maxValue)
    {
        if (errorNote.size())
        {
            LogError(errorNote);
        }

        return false;
    }

    //7.

    ret = an;
    return true;
}

std::string getExeName()
{
    std::string name;
    name.resize(PATH_MAX);
    int32_t len = readlink("/proc/self/exe", name.data(), PATH_MAX - 1);
    if (len != -1) 
    {
        std::size_t i = name.rfind('/', len - 1);
        if (i != std::string::npos)
        {
            ++i;        
        }
        else
        {
            i = 0;
        }

        return name.substr(i, len - i);
    } 
    else 
    {
        return "";
    }
}

}